﻿//
// Copyright 2024 Exhunter Technology Co.Ltd2.
//

using X18.Framework.Core.Security.Sm;

namespace X18.Framework.Core.Security.Encryptor
{
    /// <summary>
    /// SM4(国密)加密算法
    /// </summary>
    public class Sm4Encryptor : IDataEncryptor
    {
        /// <summary>
        /// 默认SecretKey
        /// </summary>
        private static readonly byte[] DefalutSecretKey = { 0x3A, 0x7F, 0xD2, 0x2E, 0x9B, 0xF1, 0x6C, 0xA5, 0x83, 0x48, 0xE7, 0x1D, 0xC4, 0x59, 0xB6, 0x00F };

        private Sm4Context GetSm4Context(byte[] key = null)
        {
            Sm4Context result = new Sm4Context();
            result.SecretKey = key ?? DefalutSecretKey;
            return result;
        }

        public byte[] EncryptToBytes(byte[] plainBytes, Sm4Context ctx)
        {
            if (plainBytes == null || plainBytes.Length <= 0)
            {
                return new byte[0];
            }
            //
            Sm4.Sm4SetKeyEnc(ctx);
            byte[] cipherBytes;
            //
            switch (ctx.Model)
            {
                case Sm4ModelType.CBC:
                    cipherBytes = Sm4.Sm4CryptCbc(ctx, Sm4.SM4_ENCRYPT, plainBytes);
                    break;
                case Sm4ModelType.ECB:
                    cipherBytes = Sm4.Sm4CryptEcb(ctx, Sm4.SM4_ENCRYPT, plainBytes);
                    break;
                default:
                    cipherBytes = Sm4.Sm4CryptCbc(ctx, Sm4.SM4_ENCRYPT, plainBytes);
                    break;
            }
            return cipherBytes;
        }

        public override byte[] EncryptToBytes(byte[] plainBytes, byte[] key = null)
        {
            Sm4Context ctx = GetSm4Context(key);
            return EncryptToBytes(plainBytes, ctx);
        }

        public byte[] DecryptFromBytes(byte[] cipherBytes, Sm4Context ctx)
        {
            if (cipherBytes == null || cipherBytes.Length <= 0)
            {
                return new byte[0];
            }
            //
            Sm4.Sm4SetKeyDec(ctx);
            byte[] plainBytes;
            //
            switch (ctx.Model)
            {
                case Sm4ModelType.CBC:
                    plainBytes = Sm4.Sm4CryptCbc(ctx, Sm4.SM4_DECRYPT, cipherBytes);
                    break;
                case Sm4ModelType.ECB:
                    plainBytes = Sm4.Sm4CryptEcb(ctx, Sm4.SM4_DECRYPT, cipherBytes);
                    break;
                default:
                    plainBytes = Sm4.Sm4CryptCbc(ctx, Sm4.SM4_DECRYPT, cipherBytes);
                    break;
            }
            return plainBytes;
        }

        public override byte[] DecryptFromBytes(byte[] cipherBytes, byte[] key = null)
        {
            Sm4Context ctx = GetSm4Context(key);
            return DecryptFromBytes(cipherBytes, ctx);
        }

        public static byte[] Encrypt(byte[] plainBytes, byte[] key = null)
        {
            Sm4Encryptor sm = new Sm4Encryptor();
            Sm4Context ctx = sm.GetSm4Context(key);
            byte[] result = sm.EncryptToBytes(plainBytes, ctx);
            return result;
        }

        public static byte[] Decrypt(byte[] cipherBytes, byte[] key = null)
        {
            Sm4Encryptor sm = new Sm4Encryptor();
            Sm4Context ctx = sm.GetSm4Context(key);
            byte[] result = sm.DecryptFromBytes(cipherBytes, ctx);
            return result;
        }
    }
}
